
#include "stdafx.h"
#include "csvline.h"
#include <utility>

CString TFILESEC::pairDescs[2];
LPCWSTR TFILESEC::tripleDescs[3] = { L"No data.", L"ansi (utf8)", L"UNICODE" };

void TFILESEC::Init()
{
	pairDescs[0].LoadString(IDS_NO_FILE_LOAD);
	pairDescs[1].LoadString(IDS_CSV_NOT_FOUND);
}

LPCWSTR TCSVLINE::szTrimChars = L"\n\t\r\x20";
LPCWSTR TCSVLINE::szQuoteApos = L"\x22\x27\x60";
const TCSVLINE::TPROC_CMP TCSVLINE::VEC_CMP_PROC[3] = 
	{ TCSVLINE::CmpProcDesc, TCSVLINE::CmpProcAsc, NULL };

int CALLBACK TCSVLINE::CmpProcAsc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	std::pair<LPCSVLINE, LPCSVLINE>	thepair((LPCSVLINE) lParam1, (LPCSVLINE) lParam2);
	CString thefirst = (thepair.first)->getSubItem(lParamSort);
	CString thesecon = (thepair.second)->getSubItem(lParamSort);
		thefirst.Trim(TCSVLINE::szQuoteApos);
		thesecon.Trim(TCSVLINE::szQuoteApos);
	return thefirst.CompareNoCase(thesecon);
}

int CALLBACK TCSVLINE::CmpProcDesc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	std::pair<LPCSVLINE, LPCSVLINE>	thepair((LPCSVLINE) lParam1, (LPCSVLINE) lParam2);
	CString thefirst = (thepair.first)->getSubItem(lParamSort);
	CString thesecon = (thepair.second)->getSubItem(lParamSort);
		thefirst.Trim(TCSVLINE::szQuoteApos);
		thesecon.Trim(TCSVLINE::szQuoteApos);
	return thesecon.CompareNoCase(thefirst);
}

bool TCSVLINE::testSec(const CString & astr, CString & aname)
	{
		if (astr.GetAt(0) != L'[') return false;
		if (astr.GetLength() < 3) return false;

		int index = astr.ReverseFind(L']');
		if (index < 2) return false;

		aname = astr.Left(index);
		aname.TrimLeft(L"[");

		return true;
	}

int TCSVLINE::dequotes(const CString & asource, LPCWSTR adelimit)
	{
		int apos(0);
		CString	thestr = asource.Tokenize(adelimit, apos);
		while (apos + 1) 
		{
			thestr.Trim(szTrimChars);
			int lastindex = thestr.GetLength() - 1;
			if (lastindex > 0)	
				if (thestr.GetAt(lastindex) == QUOTES) 
					break;

			thestr = asource.Tokenize(adelimit, apos);
		};
		return apos;
	}

 TCSVLINE::TCSVLINE(const TCSVLINE & aline) : 
	m_type(aline.m_type), m_sec(aline.m_sec),
	m_root(aline.m_root), m_code(aline.m_code)
{
	for (int i(0); i < COL_COUNT + 2; ++i)
		m_vec[i] = aline.m_vec[i]; 
}

bool TCSVLINE::loadAttr(const CString & asource)
{
	int	index(0);	//	race between: L"=,"
	WCHAR ch = asource.GetAt(0);
	if (ch == QUOTES) index = dequotes(asource, L"=,");
	else 
	if ((ch ^ COMMENT) && (ch ^ L'=')) asource.Tokenize(L"=,", index);
		else return false;

	if (--index > 0)
	if (asource.GetAt(index) == '=') 
	{
		CString thestr = asource.Left(index);
			thestr.Trim(szTrimChars);
		if (thestr.GetLength())
		{
			m_vec[0] = thestr;
				thestr = asource.Mid(++index);
				thestr.Trim(szTrimChars);
			ch = thestr.GetAt(0); 
			if (ch == QUOTES)
				index = thestr.Find(QUOTES, 1) + 1;
			else
				index = thestr.Find(COMMENT, 1);

			if (ch != COMMENT)
			{
				LPWSTR theval = (LPWSTR) thestr.operator LPCWSTR();
				if ((index + 1) >> 1) theval[index] = 0;
				m_vec[1] = theval;
			}

			return true;
		}
	}
	return false;
}

bool TCSVLINE::loadTag(const CString & asource) 
{
	WCHAR ch = asource.GetAt(0);
	if (ch == COMMENT) return false;

	int	index(0);
	CString thestr = asource.Tokenize(L",", index);
	if (ch == QUOTES)
	{
		index = dequotes(asource, L",");
		if (index > 0) thestr = asource.Left(index - 1);
	}

	if (index < 0) index = 0;	//	return false;

	* m_vec = thestr.Trim(szTrimChars);
	CString thesource = asource.Mid(index);
			thesource.Trim(szTrimChars);

	int thecol(0);
	if (index)
	for (thecol = 1; thecol < COL_COUNT; ++thecol)
	{
			ch = thesource.GetAt(0);
		if (ch == QUOTES)
		{
			index = dequotes(thesource, L",");
			if (index > 0) thestr = thesource.Left(index - 1);
		}
		else if (ch == ',')
		{
			index = 1; thestr.Empty(); 
		}
		else {
			index = 0; 
			thestr = thesource.Tokenize(L",", index);
		}

		if (index + 1)
		{
			m_vec[thecol] = thestr.Trim(szTrimChars);
			thesource = thesource.Mid(index);
			thesource.Trim(szTrimChars);
		}
			else break;
	}

	if (thecol >> 1) 
	{
		m_type = 1;
			
		if (thecol > 2)
		{
			if (thesource.IsEmpty() && (thecol == COL_COUNT))
			{
				thecol = COL_COUNT - 1;
				thesource = m_vec[thecol];
			}	

			if (thecol < COL_COUNT)
			{
				ch = 0;
				if (thesource.GetLength() > 2)
				{
					ch = thesource.GetAt(0);
					if (ch == QUOTES)
					{
						index = thesource.Find(QUOTES, 1);
						if (index + 1) m_vec[thecol] = thesource.Left(index + 1);
							else ch = 0;
					}
				}

				if (ch != QUOTES)
				{
					index = 0;
					m_vec[thecol] = thesource.Tokenize(L";", index);
				}
			}
				else m_vec[COL_COUNT] = thesource;	//	save tail 

			if (m_vec[0].GetLength()) m_root = m_vec[0];
				else if (m_vec[1].GetLength())
					m_root = m_vec[1];

				thestr = m_vec[3];
			if (!(m_root.IsEmpty()))
			if(thestr.GetLength())
			{
				thestr.Trim(szQuoteApos).MakeLower();
	//	LPWSTR opcode = (LPWSTR) thestr.operator LPCWSTR();
				LPCWSTR opcode = ::wcschr(thestr, 'x');
				if (opcode) thecol = ::swscanf(++opcode, L"%x", &m_code);
					else thecol = 0;
//				thecol = ::swscanf(thestr, L"0x%X", &m_code);
				HRESULT hr = S_OK;
				if (!thecol)
				{
					hr = ::VarUI4FromStr( thestr, 
							LOCALE_SYSTEM_DEFAULT, 
							LOCALE_NOUSEROVERRIDE,
							& m_code);
					if (hr != S_OK) m_root.Empty();
				}

				if (hr == S_OK) m_vec[3].Format(L"0x%X", m_code);
			}
				else m_vec[3] = L"0x0";

		}

		if ((m_vec[COL_COUNT]).IsEmpty()) m_vec[COL_COUNT] = m_sec;
		else {
			thestr = m_vec[COL_COUNT];
			m_vec[COL_COUNT] = m_sec;
			m_vec[COL_COUNT + 1] = thestr;
		}

		return true;
	}

	return false;
}
